<script setup>
import { onMounted, onUnmounted, ref } from 'vue';
import { Base } from '../threejs/base';
import * as THREE from 'three';
import fish from '../assets/fish.svg';
import snake from '../assets/snake.png';
import { gsap } from "gsap";
class Demo extends Base {
  mesh;
  m;
  time;
  controls = { color: 0xff0000 };
  geometry = { Geometry: 1 };
  initGui() {
    const g = this.gui.addFolder('调整这里试试');
    let colorChange = g.addColor(this.controls, 'color').name('色值');
    colorChange.onChange((value) => {
      console.log(value);
      for (let i = 0; i < this.scene.children.length; i++) {
        // 方式1
        // this.scene.children[i].material.uniforms.uColor.value.set(value); // 改变颜色为绿色
        // 方式2
        var newColor = new THREE.Color(this.controls.color);
        // 更新材质的颜色
        console.log(newColor);
        this.scene.children[i].material.uniforms.uColor.value.copy(newColor); // 如果颜色是uniform
      }
    });
    g.open();
  }

  initShader() {
    this.camera.position.set(0, 0, 4);
    this.camera.lookAt(new THREE.Vector3());
    this.renderer.setClearColor(0x160016, 1);

    this.loadImages([fish], (images) => {
      console.log(images);
      let coords = this.getImageCoords(images[0]);
      this.ini01(coords);
    });
  }
  getImageCoords(img) {
    const size = 100;
    const canvas = document.createElement('canvas');
    canvas.width = size;
    canvas.height = size;
    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, size, size);
    ctx.drawImage(img, 0, 0, size, size);
    const data = ctx.getImageData(0, 0, size, size).data;
    const imageCoords = [];
    // 过滤黑色
    for (let y = 0; y < size; y++) {
      for (let x = 0; x < size; x++) {
        const red = data[(y * size + x) * 4];
        // const green = data[(y * size + x) * 4 + 1];
        // const blue = data[(y * size + x) * 4 + 2];
        // const alpha = data[(y * size + x) * 4 + 3];
        if (red > 0 && red < 50) {
          imageCoords.push([x / size - 0.5, 0.5 - y / size]);
        }
      }
    }
    // document.body.appendChild(canvas);
    // canvas.classList.add('test-canvas');
    // canvas.style.position = 'fixed';
    // canvas.style.top = 0;
    // canvas.style.left = 0;

    return imageCoords;
  }
  loadImages(paths, whenLoaded) {
    const images = [];
    paths.forEach((path) => {
      const img = new Image();
      img.onload = function () {
        images.push(img);
        if (images.length === paths.length) {
          whenLoaded(images);
        }
      };
      img.src = path;
    });
  }
  getRandomValue(data) {
    return data[Math.floor(Math.random() * data.length)];
  }
  ini01(imageCoords) {
    const count = 10000;

    let geometry = new THREE.BufferGeometry();
    const positions = new Float32Array(count * 3);
    const positions1 = new Float32Array(count * 3);
    const scale = 3.0;
    // const offsets = new Float32Array(count);
    let offsets=[]
    console.log(offsets)
    for (let i = 0; i < count * 3; i += 3) {
      const [x, y] = this.getRandomValue(imageCoords);
      const z = Math.random();
      positions.set([x * scale, y * scale, z*-0.3], i);


      const r = Math.random() + 1;
      const angle = Math.random() * Math.PI * 2;
      const x1 = Math.cos(angle) * r;
      const y1 = Math.sin(angle) * r;
      const z1 = (Math.random() - 0.5) * 2;
      positions1.set([x1, y1, z1], i);

      // offsets.set([Math.random()], i / 3);
      offsets.push(Math.random())
    }
    console.log(offsets)
    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
    geometry.setAttribute('position1', new THREE.BufferAttribute(positions1, 3));
    // geometry.setAttribute("aOffset", new THREE.BufferAttribute(offsets, 1));
    geometry.setAttribute('aOffset', new THREE.Float32BufferAttribute(offsets, 1));

    const vertexShader = /* GLSL */ `
      attribute float aOffset;
      attribute vec3 position1;
      varying float vDepth;
      uniform float uTime;
      
      
      const float PI = 3.141592653589793238;
      // varying float vProgress;
      uniform float vProgress;
      void main() {
        vDepth=position.z;

        // float progress = abs(sin(uTime));
        // vProgress = progress;

        // vec3 newPos = position1;

        // 位置过渡
        vec3 newPos = mix(position1, position, vProgress);
        newPos.y += 0.02 * sin(aOffset * PI * 2.0 + uTime * 5.0);

        gl_Position = projectionMatrix * modelViewMatrix * vec4(newPos, 1.0);
        gl_PointSize = 12.0;

      }
    `;
    const fragmentShader = /* GLSL */ `
      varying float vDepth;
      uniform vec3 uColor;
      uniform vec3 uColor1;
      // varying float vProgress;
      uniform float vProgress;
      // https://gist.github.com/yiwenl/745bfea7f04c456e0101
      vec3 rgb2hsl(vec3 color) {
        vec3 hsl; // init to 0 to avoid warnings ? (and reverse if + remove first part)

        float fmin = min(min(color.r, color.g), color.b); //Min. value of RGB
        float fmax = max(max(color.r, color.g), color.b); //Max. value of RGB
        float delta = fmax - fmin; //Delta RGB value

        hsl.z = (fmax + fmin) / 2.0; // Luminance

        if (delta == 0.0) //This is a gray, no chroma...
        {
            hsl.x = 0.0; // Hue
            hsl.y = 0.0; // Saturation
        } else //Chromatic data...
        {
            if (hsl.z < 0.5)
                hsl.y = delta / (fmax + fmin); // Saturation
            else
                hsl.y = delta / (2.0 - fmax - fmin); // Saturation

            float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;
            float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;
            float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;

            if (color.r == fmax)
                hsl.x = deltaB - deltaG; // Hue
            else if (color.g == fmax)
                hsl.x = (1.0 / 3.0) + deltaR - deltaB; // Hue
            else if (color.b == fmax)
                hsl.x = (2.0 / 3.0) + deltaG - deltaR; // Hue

            if (hsl.x < 0.0)
                hsl.x += 1.0; // Hue
            else if (hsl.x > 1.0)
                hsl.x -= 1.0; // Hue
        }

        return hsl;
      }
      // https://github.com/Experience-Monks/glsl-hsl2rgb/blob/master/index.glsl
      float hue2rgb(float f1, float f2, float hue) {
          if (hue < 0.0)
              hue += 1.0;
          else if (hue > 1.0)
              hue -= 1.0;
          float res;
          if ((6.0 * hue) < 1.0)
              res = f1 + (f2 - f1) * 6.0 * hue;
          else if ((2.0 * hue) < 1.0)
              res = f2;
          else if ((3.0 * hue) < 2.0)
              res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;
          else
              res = f1;
          return res;
      }

      vec3 hsl2rgb(vec3 hsl) {
        vec3 rgb;
        
        if (hsl.y == 0.0) {
            rgb = vec3(hsl.z); // Luminance
        } else {
            float f2;
            
            if (hsl.z < 0.5)
                f2 = hsl.z * (1.0 + hsl.y);
            else
                f2 = hsl.z + hsl.y - hsl.y * hsl.z;
                
            float f1 = 2.0 * hsl.z - f2;
            
            rgb.r = hue2rgb(f1, f2, hsl.x + (1.0/3.0));
            rgb.g = hue2rgb(f1, f2, hsl.x);
            rgb.b = hue2rgb(f1, f2, hsl.x - (1.0/3.0));
        }   
        return rgb;
      }

      vec3 hsl2rgb(float h, float s, float l) {
          return hsl2rgb(vec3(h, s, l));
      }

      vec3 setColor(vec3 color, float depth) {
        float value = depth / -0.3 * 30.0;
        float r = clamp(color.r - value * 5.0/255.0, 0.0, 1.0);
        float g = clamp(color.g - value * 5.0/255.0, 0.0, 1.0);
        float b = clamp(color.b - value * 5.0/255.0, 0.0, 1.0);
        return vec3(r, g, b);
      }
      void main() {
        // // hsl改变颜色的l/b
        // vec3 hsl = rgb2hsl(uColor);
        // hsl.b += vDepth * 1.5;
        // vec3 color = hsl2rgb(hsl);
    
        // vec3 color = setColor(uColor, vDepth);   
        vec3 color = mix(uColor1, uColor, vProgress); 
        color = setColor(color, vDepth);
        // 粒子变圆
        
        float dist = distance(gl_PointCoord, vec2(0.5));
        float mask = smoothstep(0.5, 0.499, dist);
        gl_FragColor = vec4(color, 1.0*mask);
      }
    `;
    let material = new THREE.ShaderMaterial({
      uniforms: {
        uTime: { value: 0 },
        vProgress: { value: 0 },
        uColor: { value: new THREE.Color(0xff0000) },
        uColor1: { value: new THREE.Color("rgb(139,195,74)") },
      },
      vertexShader,
      fragmentShader,
      transparent: true,
      depthTest: false,
      depthWrite: false,
    });
    const mesh = new THREE.Points(geometry, material);
    this.scene.add(mesh);
  }

  renderContent() {
    // this.time += 0.05;
    let time = this.clock.getElapsedTime();
    for (let i = 0; i < this.scene.children.length; i++) {
      this.scene.children[i].material.uniforms.uTime.value = time;
      this.scene.children[i].rotation.y = time / 100;
    }
  }
}

let ins;
const dom = ref();
let run=()=>{
  console.log(ins.scene.children[0].material.uniforms.vProgress)
  gsap.to(ins.scene.children[0].material.uniforms.vProgress, {
    value: 1,
    onComplete: () => {
      // animating = false;
      // geometry.attributes.position.array = geometryAttributes[current];
      // geometry.attributes.position.needsUpdate = true;
      // material.uniforms.uColor.value = color;
      // material.uniforms.uProgress.value = 0;
      // ins.scene.children[0].material.uniforms.vProgress.value=0
    },
  });
}
onMounted(() => {
  ins = new Demo().init(dom.value);
});
onUnmounted(() => {
  ins.dispose();
});

const text = `
本示例主要学习了通过 uniforms 向着色器传递数据。示例主要代码如下：
\`\`\`
const m = new THREE.ShaderMaterial({
  uniforms: {
    uColor: { value: new THREE.Color(0xff0000) }
  },
  vertexShader: \`
    void main() {
      
      // position 是顶点的local坐标(Model坐标)
      // Model坐标 * ModelMatrix = World坐标；World坐标 * ViewMatrix = Camera坐标；Camera坐标 * ProjectionMatrix = 投影坐标

      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }\`,
  fragmentShader: \`
    uniform vec3 uColor;  // 接收 uniforms 传过来的数据
    
    void main() {
      gl_FragColor = vec4(uColor, 1.0);
    }\`
});
\`\`\`
`;
</script>

<template>
  <div class="shader-box" ref="dom" @click="run"></div>
  <v-md-preview :text="text"></v-md-preview>
</template>

<style scoped></style>
